Skip to content

POC: Parallel LPT buckets - #8496

Open
webard wants to merge 3 commits into
rectorphp:mainfrom
webard:poc/parallel-lpt-buckets
Open

webard wants to merge 3 commits into
rectorphp:mainfrom
webard:poc/parallel-lpt-buckets

Conversation

@webard

@webard webard commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Created with the help of Claude.

A proof of concept for testing, not a merge candidate. No tests yet, an opt-in experimental flag, and one unresolved trade-off (memory) that would have to be settled before this could ship. Opening it to put the approach and the numbers in front of people who can try it on their own codebases.

Follows up on #8494, and specifically @samsonasik's comment there: #8494 (comment)

All of it behind --lpt, opt-in. Without the flag the default path is untouched.

scheduler wall peak RSS
current 152.2 s 751 MB
LPT, static buckets 127.8 s 938 MB
LPT + stealing 113.4 / 122.1 s 902 MB

jobSize sweep, LPT + stealing, 14 workers:

jobSize wall diffs
1 98.8 s 3 338
2 90.7 / 91.4 s 3 338
4 96.7 / 99.2 s 3 338
8 104.6 s 3 338
16 113.4 s 3 338
50 118.1 s 3 338
150 127.5 s 3 237 — timed out

Best current 152.2 s → best --lpt 90.7 s, i.e. -40 %. At identical worker count and jobSize, -25 %.

Every run produces the same 3 338 diffs (sha over the file-sorted diff list) and the same 2 errors, except jobSize: 150.

vendor/bin/rector process --dry-run --clear-cache --no-progress-bar
vendor/bin/rector process --dry-run --clear-cache --no-progress-bar --lpt

@webard
webard marked this pull request as draft September 14, 2026 18:50
@samsonasik

samsonasik commented Sep 15, 2026 •

Copy link
Copy Markdown
Member

Thank you @webard, I tested locally main vs your pr branch and your pr branch looks faster 👍

main branch: 14.645 seconds.

➜ (main) time bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar       

129.32s user 12.90s system 971% cpu 14.645 total

poc/parallel-lpt-buckets branch with use of --lpt: 11.455 seconds.

➜ (poc/parallel-lpt-buckets) time bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar --lpt 
                                                                                                                         
108.58s user 10.59s system 1040% cpu 11.455 total

@webard

webard commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

Thank you @samsonasik for testing this.

I'm also seeing a big improvement in my projects. However, in the larger ones the numbers show that increasing jobSize in the original implementation sometimes still gives better results. I think keeping this flag as an optional setting would be a good idea. Let's also wait for @TomasVotruba opinion.

@TomasVotruba
TomasVotruba force-pushed the poc/parallel-lpt-buckets branch from 03d027f to e652152 Compare October 1, 2026 08:31
@samsonasik

Copy link
Copy Markdown
Member

@webard I found that Cluster large files into one worker can improve performance on StructArmed, it is about 1.6x faster on running StructArmed on spiral-framework with the tweak, especially on many files, see this commit:

boundwize/structarmed@d1d65d7

and it shows faster 1.6x from 0.64s to 0.39s:

Before:

structarmed-speed-01811.mp4

After

structarmed-0193-faster.mov

that's can be next experiment for it.

@samsonasik samsonasik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good to me for first experimental, additional LPT improvement can be improved more later 👍

@TomasVotruba

TomasVotruba commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

@samsonasik Can you test this on laravel (https://github.com/laravel/framework) and Symfony projects ()https://github.com/symfony/symfony) and compare time+memory before/after?

I want to see something heavier

@samsonasik

samsonasik commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

@TomasVotruba sure, here the result:

On Laravel framework:

Before : 1 minutes 30 seconds

➜  time bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar ../laravel-framework/src ../laravel-framework/tests 
                                                                                                                        
 [OK] 2683 files would have been changed (dry-run) by Rector                                                            
                                                                                                     
bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar    713.50s user 16.98s system 806% cpu 1:30.56 total

After (with --lpt option in cli): 1 minutes 10 seconds

➜  time bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar ../laravel-framework/src ../laravel-framework/tests --lpt
                                                                                                                        
 [OK] 2683 files would have been changed (dry-run) by Rector                                                            
                                                                                                                        
bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar --lpt  763.90s user 17.19s system 1109% cpu 1:10.41 total

On Symfony framework:

Before : 4 minutes

➜  time bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar ../symfony/src
                                                                                                                        
 [OK] 2683 files would have been changed (dry-run) by Rector                                                            
                                                                                                     
bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar ../symfony/sr  2348.09s user 118.16s system 1026% cpu 4:00.18 total

After (with --lpt option in cli): 2 minutes 23 seconds

➜  time bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar ../symfony/src --lpt
                                                                                                                        
 [OK] 2683 files would have been changed (dry-run) by Rector                                                            
                                                                                                                        
bin/rector --no-diffs --dry-run --clear-cache --no-progress-bar ../symfony/sr  1327.72s user 163.84s system 1035% cpu 2:23.99 total

The summary:

For laravel: this PR --lpt option faster 22.25%
For symfony: this PR --lpt option faster 40.05%

@TomasVotruba
TomasVotruba marked this pull request as ready for review October 9, 2026 19:09
Copilot AI balanced review requested due to automatic review settings October 9, 2026 19:09
@TomasVotruba
TomasVotruba force-pushed the poc/parallel-lpt-buckets branch from e652152 to ad7c011 Compare October 9, 2026 19:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The experimental path has unresolved result-loss and error-limit defects alongside the acknowledged memory trade-off.

4 open findings
What changed in this PR

Proof of concept for an opt-in LPT scheduler that balances files by size, supports work stealing, and retains warm workers for improved parallel performance.

Changes:

  • Adds LPT bucket scheduling and experimental processing behind --lpt.
  • Extracts shared worker-result collection logic.
  • Documents benchmarks, memory costs, and unresolved risks.
File Description
src/​Parallel/​Experimental/​ValueObject/​BucketSchedule.php Stores per-worker job buckets.
src/​Parallel/​Experimental/​LptScheduleFactory.php Creates size-balanced LPT buckets.
src/​Parallel/​Experimental/​ExperimentalParallelFileProcessor.php Runs persistent workers with work stealing.
src/​Parallel/​Application/​ParallelResultCollector.php Centralizes result aggregation.
src/​Parallel/​Application/​ParallelFileProcessor.php Uses the shared result collector.
src/​Console/​ProcessConfigureDecorator.php Registers --lpt.
src/​Configuration/​Option.php Defines the LPT option.
src/​Application/​ApplicationFileProcessor.php Selects the experimental scheduler.
PARALLEL_LPT_POC_NOTES.md Records design, benchmarks, and risks.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

)));
}

return $parallelResultCollector->createProcessResult();
&$bucketKeyByIdentifier,
$postFileCallback,
&$systemErrorsCount,
&$reachedInternalErrorsCountLimit,
Comment thread PARALLEL_LPT_POC_NOTES.md
@@ -0,0 +1,349 @@
# PoC: LPT bucket scheduling for parallel run
/**
* @experimental Opt-in to the LPT bucket scheduler
* @see \Rector\Parallel\Experimental\LptScheduleFactory
* @var string
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants